package com.xiaoshuidi.cloud.module.contract.api.finance;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.tenant.core.util.TenantUtils;
import com.xiaoshuidi.cloud.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.company.CompanyContractRentDataRespVO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.OrderFeesDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.RentOrderDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.*;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.SettlementMapper;
import com.xiaoshuidi.cloud.module.contract.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderApprovedStatusEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderPayStatusEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractNodeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractSettlementTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractStatusEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.CustomerTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.settlement.SettlementStatusEnum;
import com.xiaoshuidi.cloud.module.contract.service.bill.OrderFeesService;
import com.xiaoshuidi.cloud.module.contract.service.bill.RentOrderService;
import com.xiaoshuidi.cloud.module.contract.service.contract.*;
import com.xiaoshuidi.cloud.module.finance.api.finance.FinancePaymentApi;
import com.xiaoshuidi.cloud.module.finance.api.finance.dto.FinancePaymentDTO;
import com.xiaoshuidi.cloud.module.finance.enums.finance.DirectionEnum;
import com.xiaoshuidi.cloud.module.finance.enums.finance.SourceBizTypeEnum;
import com.xiaoshuidi.cloud.module.system.api.tenant.TenantApi;
import com.xiaoshuidi.cloud.module.system.api.tenant.dto.TenantDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.module.contract.enums.ApiConstants.ZERO;

/**
 * 获取交易流水需要的数据
 */
@RestController
@FeignClient(name = "${spring.application.name}")
@Slf4j
public class FinancePaymentApiImpl implements FinancePaymentApi {
    @Resource
    private RentOrderService rentOrderService;
    @Resource
    private ContractRoomService contractRoomService;
    @Resource
    private TenantApi tenantApi;
    @Resource
    private ContractHouseOwnerService ownerService;
    @Resource
    private CompanyContractService companyContractService;
    @Resource
    private CustomerCompanyService customerCompanyService;
    @Resource
    private OrderFeesService orderFeesService;

    @Resource
    private SettlementMapper settlementMapper;

    @Override
    public CommonResult<FinancePaymentDTO> createPayment(String sourceBizId, String sourceBizType) {
        return TenantUtils.executeIgnoreAndReturn(() -> {
            if (SourceBizTypeEnum.COMPANY_RENT_ORDER.name().equals(sourceBizType)) {
                // 企业账单
                return buildCompanyOrder(sourceBizId);
            } else if (SourceBizTypeEnum.SETTLEMENT_BILL.name().equals(sourceBizType)) {
                // 企业账单
                return buildSettleMent(sourceBizId);
            } else {
                RentOrderDO rentOrder = rentOrderService.getContractRentOrder(Long.valueOf(sourceBizId));
                if (rentOrder == null) {
                    return CommonResult.error(ErrorCodeConstants.ROOM_ORDER_NOT_EXISTS);
                }
                if (!OrderApprovedStatusEnum.HAVE_TAKEN_EFFECT.getCode().equals(rentOrder.getApprovedStatus())
                        && !OrderApprovedStatusEnum.NO_AUDIT_REQUITED.getCode().equals(rentOrder.getApprovedStatus())) {
                    return CommonResult.error(ErrorCodeConstants.RENT_ORDER_CANNOT_PAY);
                }
                // 已支付
                if (OrderPayStatusEnum.PAID.getCode().equals(rentOrder.getPayStatus())) {
                    return CommonResult.error(ErrorCodeConstants.ROOM_ORDER_ALREADY_PAID);
                }

                if (SourceBizTypeEnum.OWNER_ORDER.name().equals(sourceBizType)) {
                    // 业主账单
                    return buildOwnerOrder(rentOrder);
                } else {
                    return buildCustomerOrder(rentOrder);
                }
            }
        });
    }

    /**
     * 退租清算单
     */
    private CommonResult<FinancePaymentDTO> buildSettleMent(String sourceBizId) {
        SettlementDO settlementDO = settlementMapper.selectById(sourceBizId);
        if (ObjectUtil.isEmpty(settlementDO)) {
            log.error("异常{}", ErrorCodeConstants.SETTLEMENT_SETTLED_NOT_EXIST);
        }
        String subject = "租客清算单";
        BigDecimal rental = BigDecimal.ZERO;
        LocalDate starTime = null;
        LocalDate endTime = null;
        if (ContractSettlementTypeEnum.COMPANY_BATCH.getValue().equals(settlementDO.getSettlementType())) {
            subject = "企业清算单";
            LambdaQueryWrapper<SettlementDO> eq =
                    new LambdaQueryWrapper<SettlementDO>().eq(SettlementDO::getParentSettlementId,
                            settlementDO.getId());
            List<SettlementDO> settlementDOS = settlementMapper.selectList(eq);
            if (CollectionUtil.isEmpty(settlementDOS)) {
                log.error("企业批量清算单id为【{}】不存在清算单子项", sourceBizId);
            }
            if (CollectionUtil.isNotEmpty(settlementDOS)) {
                List<Long> contractIds =
                        settlementDOS.stream().map(SettlementDO::getContractId).collect(Collectors.toList());
                List<ContractRoomDO> contractRoomDOS = contractRoomService.getList(contractIds);
                rental = contractRoomDOS.stream().map(ContractRoomDO::getMonthRent)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            //企业大合同开始结束时间
            CompanyContractRentDataRespVO companyContract =
                    companyContractService.getByCompanyContractId(settlementDO.getContractId());
            if (ObjectUtil.isNotEmpty(companyContract)) {
                starTime = companyContract.getStartTime();
                endTime = companyContract.getEndTime();
            }
        } else {
            ContractRoomDO contractRoomDO = contractRoomService.get(settlementDO.getContractId());
            if (ObjectUtil.isNotEmpty(contractRoomDO)) {
                starTime = contractRoomDO.getStartTime();
                endTime = contractRoomDO.getEndTime();
            }
            rental = contractRoomDO.getMonthRent();
        }


        FinancePaymentDTO.FinancePaymentDTOBuilder builder = FinancePaymentDTO.builder();
        return CommonResult.success(builder.subject(subject)
                .expireInMinute(30)
                .roomContractNo(settlementDO.getContractNo())
                .roomContractId(settlementDO.getId())
                .roomRentOrderNo(sourceBizId)
                .roomRentOrderStart(starTime)
                .roomRentOrderEnd(endTime)
                .renter(settlementDO.getCustomerName())
                .trader(settlementDO.getCustomerName())
                .rentCustomer(settlementDO.getCustomerName())
                .roomId(settlementDO.getRoomId())
                .roomName(settlementDO.getRoomName())
                .apartmentId(settlementDO.getApartmentId())
                .apartmentName(settlementDO.getApartmentName())
                .direction(DirectionEnum.IN.getValue())
                .tradeAmount(settlementDO.getAmount())
                .tradeTime(settlementDO.getEvictionTime().atStartOfDay())
                .memberId(0L)
                .rental(rental)
                .tenantId(settlementDO.getTenantId())
                .deptId(settlementDO.getDeptId())
                .build());
    }

    /**
     * 企业账单
     */
    private CommonResult<FinancePaymentDTO> buildCompanyOrder(String sourceBizId) {
        List<RentOrderDO> rentListByBatchNo = rentOrderService.getRentListByBatchNo(sourceBizId);
        if (CollectionUtils.isEmpty(rentListByBatchNo)) {
            return CommonResult.error(ErrorCodeConstants.ROOM_ORDER_NOT_EXISTS);
        }
        RentOrderDO rentOrder = rentListByBatchNo.get(ZERO);
        CompanyContractDO contract = companyContractService.getCompanyContractBySubContractId(rentOrder.getBusinessId());
        if (Objects.isNull(contract)){
            return CommonResult.error(ErrorCodeConstants.COMPANY_CONTRACT_NOT_EXISTS);
        }
        CustomerCompanyDO company = customerCompanyService.getCompanyDoById(contract.getCustomerCompanyId());
        if (Objects.isNull(company)){
            return CommonResult.error(ErrorCodeConstants.COMPANY_NOT_EXISTS);
        }

        // 待付租金 例:899.69
        BigDecimal rental = rentOrder.getRentAmount();
        rental = rental.subtract(rentOrder.getDiscountAmount() == null ? BigDecimal.ZERO :
                rentOrder.getDiscountAmount());
        // 6.0系统编辑账单
        List<OrderFeesDO> l = orderFeesService.getOrderFeesByOrderId(rentOrder.getId());
        //获取该账单下全部流出总计 例:0
        BigDecimal extrasAmount = l.stream().filter(f -> f.getFlowType() == 1)
                .map(OrderFeesDO::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        //获取该账单下所有租金项累计 例:899.69
        BigDecimal paidRental = l.stream().filter(f -> ApiConstants.RENT_FEE_ID.equals(f.getFeeId()))
                .map(OrderFeesDO::getPaidAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        //租金 - 流出 例:899.69
        rental = rental.subtract(extrasAmount);
        //租金明细项总计小于 租金
        if (paidRental.compareTo(rental) < 0) {
            //租金 - 租金项累计
            rental = rental.subtract(paidRental);
        } else {
            rental = BigDecimal.ZERO;
        }

        FinancePaymentDTO.FinancePaymentDTOBuilder builder = FinancePaymentDTO.builder();
        return CommonResult.success(builder.subject("企业账单支付")
                .expireInMinute(30)
                .roomContractNo(contract.getContractNo())
                .roomContractId(contract.getId())
                .roomRentOrderNo(sourceBizId)
                .roomRentOrderStart(rentOrder.getStartTime())
                .roomRentOrderEnd(rentOrder.getEndTime())
                .renter(company.getCompanyName())
                .trader(company.getCompanyName())
                .rentCustomer(company.getCompanyName())
                .roomId(rentOrder.getRoomId())
                .roomName(rentListByBatchNo.stream().map(RentOrderDO::getRoomName).distinct().collect(Collectors.joining(",")))
                .apartmentId(rentOrder.getApartmentId())
                .apartmentName(rentOrder.getApartmentName())
                .direction(DirectionEnum.IN.getValue())
                .tradeAmount(rentListByBatchNo.stream().map(m -> m.getTotalAmount().subtract(m.getPaidRentUtilities())).reduce(BigDecimal.ZERO, BigDecimal::add))
                .tradeTime(rentOrder.getOughtPayTime().atStartOfDay())
                .memberId(0L)
                .rental(rental)
                .tenantId(contract.getTenantId())
                .deptId(contract.getDeptId())
                .build());
    }

    /**
     * 租客账单
     */
    private CommonResult<FinancePaymentDTO> buildCustomerOrder(RentOrderDO rentOrder){
        FinancePaymentDTO.FinancePaymentDTOBuilder builder = FinancePaymentDTO.builder();
        ContractRoomDO contract = contractRoomService.get(rentOrder.getBusinessId());
        if (contract == null) {
            return CommonResult.error(ErrorCodeConstants.CONTRACT_NOT_EXISTS);
        }
//        // 续租合同账单
//        if (ContractNodeEnum.RENEWAL.getCode().equals(contract.getContractNode())) {
//            if ((ContractStatusEnum.ACTIVE.getCode().equals(contract.getContractStatus())
//                    || ContractStatusEnum.CHECK_IN.getCode().equals(contract.getContractStatus()))
//                    && contract.getChangeEffectiveTime() != null && contract.getChangeEffectiveTime().plusHours(2).isBefore(LocalDateTime.now())
//                    && CustomerTypeEnum.PERSONAL.getCode().equals(contract.getCustomerType())
//                    && rentOrder.getNum() == 1 && OrderTypeEnum.DEFAULT.getCode().equals(rentOrder.getOrderType())
//            ) {
//                log.error("续租合同首期账单支付超期 {}", rentOrder.getId());
//                return CommonResult.error(500, "超出账单付款期限, 无法支付");
//            }
//        }

        String renter = contract.getCustomerName();
        if (CustomerTypeEnum.COMPANY.getCode().equals(contract.getCustomerType())) {
            CompanyContractDO companyContract = companyContractService.getById(contract.getCompanyContractId());
            if (companyContract == null) {
                return CommonResult.error(ErrorCodeConstants.CONTRACT_NOT_EXISTS);
            }
            renter = companyContract.getCompanyName();
        }
        // 待付租金
        BigDecimal rental = rentOrder.getRentAmount();
        rental = rental.subtract(rentOrder.getDiscountAmount() == null ? BigDecimal.ZERO : rentOrder.getDiscountAmount());
        // 6.0系统编辑账单
        List<OrderFeesDO> l = orderFeesService.getOrderFeesByOrderId(rentOrder.getId());
        BigDecimal extrasAmount = l.stream().filter(f -> f.getFlowType() == 1)
                .map(OrderFeesDO::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal paidRental = l.stream().filter(f -> ApiConstants.RENT_FEE_ID.equals(f.getFeeId()))
                .map(OrderFeesDO::getPaidAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        rental = rental.subtract(extrasAmount);
        if (paidRental.compareTo(rental) < 0) {
            rental = rental.subtract(paidRental);
        } else {
            rental = BigDecimal.ZERO;
        }
        return CommonResult.success(builder.subject("账单支付")
                .expireInMinute(30)
                .roomContractNo(contract.getContractNo())
                .roomContractId(contract.getId())
                .roomRentOrderNo(rentOrder.getOrderNo())
                .roomRentOrderStart(rentOrder.getStartTime())
                .roomRentOrderEnd(rentOrder.getEndTime())
                .renter(renter)
                .trader(contract.getCustomerName())
                .rentCustomer(contract.getCustomerName())
                .roomId(rentOrder.getRoomId())
                .roomName(rentOrder.getRoomName())
                .apartmentId(rentOrder.getApartmentId())
                .apartmentName(rentOrder.getApartmentName())
                .direction(DirectionEnum.IN.getValue())
                .tradeAmount(rentOrder.getTotalAmount()
                        .subtract(rentOrder.getCouponDiscount() == null ? BigDecimal.ZERO : rentOrder.getCouponDiscount())
                        .subtract(rentOrder.getPaidRentUtilities()))
                .tradeTime(rentOrder.getOughtPayTime().atStartOfDay())
                .memberId(contract.getMemberId())
                .rental(rental)
                .deptId(contract.getDeptId())
                .tenantId(contract.getTenantId())
                .build()
        );
    }

    /**
     * 业主账单
     */
    private CommonResult<FinancePaymentDTO> buildOwnerOrder(RentOrderDO rentOrder){
        FinancePaymentDTO.FinancePaymentDTOBuilder builder = FinancePaymentDTO.builder();
        ContractHouseOwnerDO houseOwner = ownerService.getHouseOwner(rentOrder.getBusinessId());
        if (houseOwner == null) {
            return CommonResult.error(ErrorCodeConstants.HOUSE_OWNER_NOT_EXISTS);
        }
        CommonResult<TenantDTO> tenant = tenantApi.getTenant(houseOwner.getTenantId());
        log.info("查询租户信息，请求参数：{}，返回参数：{}", houseOwner.getTenantId(), tenant);
        String renter = "";
        if (Objects.nonNull(tenant) && Objects.nonNull(tenant.getData())){
            renter = tenant.getData().getName();
        }
        return CommonResult.success(builder.subject("业主账单支付")
                .expireInMinute(30)
                .roomContractNo(houseOwner.getContractNo())
                .roomContractId(houseOwner.getId())
                .roomRentOrderNo(rentOrder.getOrderNo())
                .roomRentOrderStart(rentOrder.getStartTime())
                .roomRentOrderEnd(rentOrder.getEndTime())
                .renter(renter)
                .trader(houseOwner.getOwnerName())
                .rentCustomer(houseOwner.getOwnerName())
                .roomId(rentOrder.getRoomId())
                .roomName(rentOrder.getRoomName())
                .apartmentId(rentOrder.getApartmentId())
                .apartmentName(rentOrder.getApartmentName())
                .direction(DirectionEnum.IN.getValue())
                .tradeAmount(rentOrder.getTotalAmount().subtract(rentOrder.getPaidRentUtilities()))
                .tradeTime(rentOrder.getOughtPayTime().atStartOfDay())
                .tenantId(houseOwner.getTenantId())
                .deptId(houseOwner.getDeptId())
                .build());
    }
}
